#pragma once
#include "Precompile.h"
#include "Mutex.h"
#include "EventHandler.h"
#include "EventConnection.h"

namespace Core{
	enum ParamRegulation { PARAM_UNUSED };
	template<typename param1 = ParamRegulation>
	class Event : public EventBase{
	public:
		Event():
		  m_handlerMapMutex(ThreadLib::ThreadFactory::spawnMutex()){}

		// Iterates through the registered listeners and executes their function.
		void invoke(param1 param){
			m_handlerMapMutex->lock();
			std::map<void*,boost::shared_ptr<EventHandlerBase<param1>>>::iterator itr = m_handlers.begin();
			while(itr != m_handlers.end()){
				itr->second->execute(param);
				itr++;
			}
			m_handlerMapMutex->unlock();
		}

		void invoke(){
			m_handlerMapMutex->lock();
			std::map<void*,boost::shared_ptr<EventHandlerBase<param1>>>::iterator itr = m_handlers.begin();
			while(itr != m_handlers.end()){
				itr->second->execute();
				itr++;
			}
			m_handlerMapMutex->unlock();
		}
		
		// Registers a listener on the event.
		template<class Reg>
		boost::shared_ptr<EventConnection> registerHandler(Reg* r, void (Reg::*memFn)(param1)){
			m_handlerMapMutex->lock();
			m_handlers[r] = boost::shared_ptr<EventHandlerBase<param1>>(new EventHandler<Reg,param1>(r,memFn));
			m_handlerMapMutex->unlock();
			return boost::shared_ptr<EventConnection>(new EventConnection(r,this));
		}

		template<class Reg>
		boost::shared_ptr<EventConnection> registerHandler(Reg* r, void (Reg::*memFn)()){
			m_handlerMapMutex->lock();
			m_handlers[r] = boost::shared_ptr<EventHandlerBase<param1>>(new EventHandler<Reg,param1>(r,memFn));
			m_handlerMapMutex->unlock();
			return boost::shared_ptr<EventConnection>(new EventConnection(r,this));
		}
	private:
		void unregisterHandler(void* r){
			m_handlerMapMutex->lock();
			m_handlers.erase(r);
			m_handlerMapMutex->unlock();
		}

		boost::shared_ptr<ThreadLib::Mutex> m_handlerMapMutex;
		std::map<void*,boost::shared_ptr<EventHandlerBase<param1>>> m_handlers;
	};
}